///////////////////////////////////////////////////////////////////////////
// Copyright 2009 Arabic Game Developer Network, All rights reserved
// www.agd-online.com - info@agdn-online.com
//
// File: core2.cpp
// Description: Defines the exported functions for applications.
//
///////////////////////////////////////////////////////////////////////////

// This file is part of kvalleyX.
// 
// kvalleyX is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// kvalleyX is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with kvalleyX.  If not, see <http://www.gnu.org/licenses/>.

#include "core2.h"
#include "chambers.h"
#include <iostream>
///TODO: include based on preconfigured(autogenerated) preprocessor defines.
#include "sdlrenderer.h"
#include "sdlinput.h"
#include "sdlsoundmanager.h"
#include "sdltimemanager.h"
#include "sdleventmanager.h"


namespace CopyrightsAr
{
//#include "copyrights_ar.png.cpp"
}

namespace CopyrightsEn
{
//#include "copyrights_en.png.cpp"
}

namespace CoreLib
{
#define COPYRIGHT_FILE "valley2_copyright.png"
///////////////////////////////////////////////////////////////////////////
// Class: AppState
// Purpose:
///////////////////////////////////////////////////////////////////////////
///TODO: reveiw the possibility of merging with Core2 or dissolve into
/// several specialized classes (i.e renderer, sound, events...)
class AppState// : public DSKRS::AppInstance
{
	private:
		boost::scoped_ptr<Renderer> rendererPtr;
		boost::scoped_ptr<InputManager> inputManagerPtr;
		boost::scoped_ptr<AudioManager> soundManagerPtr;
		boost::scoped_ptr<TimeManager> timerPtr;
		boost::scoped_ptr<EventManager> eventManagerPtr;
		bool quit;
	public:
		BaseApp& app;
		int m_iFPS;
		//Splash m_Copyrights[2];
		
	private:
		void setQuit();
	public:
		AppState(BaseApp& app);
		virtual ~AppState();
		virtual bool OnIdle(uint32_t ellapsedTime);
			
		bool init(unsigned int screenWidth, unsigned int screenHeight, 
		bool fullScreen);
		void SwitchFullscreen(void);
		bool LoadConfig(void);
		bool showWindow(void);
		bool audioLoad(int slot, const char *fileName);
		bool drawImage(const char *fileName, int x = 0, int y = 0);
		void run(uint32_t fpms);
		inline EventManager& getEventManager() const;
		inline InputManager& getInputManager() const;
		inline bool isQuit() const;
};

////////////////// GameApp Class Implementation //////////////////////////////
AppState::AppState(BaseApp& app) :
	app(app), quit(false),
	///TODO: add code to init backends based on configuaration
	rendererPtr(new SDLRenderer()),
	inputManagerPtr(new SDLInputManager()),
	soundManagerPtr(new SDLSoundManager()),
	timerPtr(new SDLTimeManager()),
	eventManagerPtr(new SDLEventManager())
{
	std::cerr << "Hello AppState::AppState\n";
}

AppState::~AppState()
{
	std::cerr << "Goodbye AppState::~AppState\n";
	ChamberDrawShutdown();
}

bool AppState::init(unsigned int screenWidth, unsigned screenHeight, 
					bool fullScreen)
{
	boost::signals::connection connection;
	// Init the render system
	std::cerr << "AppState::init: Initializing the renderer...\n";
	if(!rendererPtr->init(screenWidth, screenHeight, fullScreen))
		return false;
	std::cerr << "AppState::init: Renderer initialized\n";
	// Init the the input system
	std::cerr << "AppState::init: Initializing Input...\n";
	if(!inputManagerPtr->init())
		return false;
	std::cerr << "AppState::init: Input initialized\n";
	// init the audio system
	std::cerr << "AppState::init: Initializing Audio...\n";
	if(!soundManagerPtr->init())
		return false;
	std::cerr << "AppState::init: Audio initialized\n";
	// Init the Event Manager
	std::cerr << "AppState::init: Initializing the Event Manager...\n";
	eventManagerPtr->init();
	connection = eventManagerPtr->connect_quit(
		boost::bind(&AppState::setQuit, this));
	if(connection.blocked())
		return false;
	std::cerr << "AppState::init: Event Manager initialized\n";
	// init ChamberDraw
	//ChamberDrawInit();
	//Finally, init the App
	std::cerr << "AppState::init: Initializing the App...\n";
	return app.init();
	std::cerr << "AppState::init: App initialized\n";
}

bool AppState::OnIdle(uint32_t ellapsedTime)
{
	if(!app.update())
		return false;
// 	if(!app.OnDraw(ellapsedTime))
// 		return false;
	return true;
}

bool AppState::showWindow(void)
{
	std::cerr << "Hello AppState::showWindow\n";
	return rendererPtr->showWindow();
}

bool AppState::audioLoad(int slot, const char *fileName)
{
	std::cerr << "Hello AppState::audioLoad\n";
	///NOTE: This function was in the SoundManager class! move if necessary.
// 	return soundManagerPtr->load(slot, fileName);
}

bool AppState::drawImage(const char *fileName, int x, int y)
{
	std::cerr << "Hello AppState::drawImage\n";
	return rendererPtr->drawImage(fileName, x, y);
}

inline bool AppState::isQuit() const
{
	return quit;
}

void AppState::setQuit()
{
	std::cerr << "Hi, quit baby\n";
	quit = true;
}

void AppState::run(uint32_t fpms)
{
	std::cerr << "Hello AppState::run\n";
	uint32_t ellapsedTime = 0;
	std::cerr << "frame time"<<fpms<<"\n";
	// the game loop
	Event updateEvent(Event::UPDATE_EVENT);
	Event renderEvent(Event::RENDER_EVENT);
	///TODO: handle exceptions here (and everywhere else)
	while(!isQuit())
	{
		ellapsedTime = timerPtr->getEllapsedTime();
		//std::cerr<<"ellapsed time "<<ellapsedTime<<"ms\n";
		if(ellapsedTime > fpms)
		{
			// It's 1'Oclock and time for lunch!
			eventManagerPtr->fireEvent(renderEvent);
			timerPtr->reset();
			///TODO: move rendering to the renderEvent Handler.
			//rendererPtr->renderFrame();
		}
		else
		{
			// update game
			eventManagerPtr->fireEvent(updateEvent);
			//TODO: Remove me
			//timerPtr->wait(100);
		}
		// dispatch events
		///TODO: consider threading
		eventManagerPtr->update();
	}
	///TODO: add cleanup code here
	std::cerr << "Goodbye AppState::run\n";
}

inline EventManager& AppState::getEventManager() const
{
	return *eventManagerPtr;
}

inline InputManager& AppState::getInputManager() const
{
	return *inputManagerPtr;
}

boost::scoped_ptr<AppState> g_AppStatePtr;


/////////////////// Global Functions //////////////////////////////////////

Core2::Core2()
{
}

// Return singleton instance
Core2& Core2::getInstance()
{
	static Core2 core;
	return core;
}

bool Core2::init(BaseApp& app, unsigned int screenWidth,
						 unsigned int screenHeight, bool fullScreen)
{
	///TODO: dispose of all globals
	g_AppStatePtr.reset(new AppState(app));
	if(!g_AppStatePtr->init(screenWidth, screenHeight, fullScreen))
		return false;
	if(!g_AppStatePtr->showWindow())
		return false;
	// Display copyright
	g_AppStatePtr->drawImage(COPYRIGHT_FILE);
	return true;
}

/*// Init the library. Editor version.
CORELIB_API bool LibInit(class BaseApp *pApp,HWND hWndOwner,WNDPROC wndProc,int
iFPS)
{
	return false;
}*/

void Core2::run(int fps)
{
	///TODO: dispose of all globals
	std::cerr << "Hello Core2::run\n";
	if (!g_AppStatePtr) return;

	g_AppStatePtr->m_iFPS = fps;
	g_AppStatePtr->run(static_cast<uint32_t>(1000.0f/(float)fps));
}

CORELIB_API void LibRun(void)
{
	/*if (!g_AppStatePtr) return;
	g_AppStatePtr->OnIdle();
	*/
}

CORELIB_API void LibSwitchFullScreen(void)
{
	if (!g_AppStatePtr) return;
}

void Core2::shutdown(void)
{
}

EventManager& Core2::getEventManager() const
{
	return g_AppStatePtr->getEventManager();
}

InputManager& Core2::getInputManager() const
{
	return g_AppStatePtr->getInputManager();
}

CORELIB_API bool AudioLoad(int iSlot,const char *pszWavFileName)
{
	std::cerr << "Hello CoreLib::LibRun\n";
	std::cerr << "loading image: " << pszWavFileName << std::endl;
	///TODO: verify what does iSolot means.
	if (!g_AppStatePtr) return false;
	return g_AppStatePtr->audioLoad(iSlot, pszWavFileName);
}

CORELIB_API void AudioPlay(int iSlot)
{
	if (!g_AppStatePtr) return;
	/*if (g_AppStatePtr->m_aSounds[iSlot].GetVolume() < 0)
		return;
	g_AppStatePtr->m_aSounds[iSlot].Seek(0);
	g_AppStatePtr->m_aSounds[iSlot].Play();
	*/
}

CORELIB_API void AudioStop(int iSlot)
{
	if (!g_AppStatePtr) return;
// 	g_AppStatePtr->m_aSounds[iSlot].Stop();
}

CORELIB_API void AudioRewind(int iSlot)
{
	if (!g_AppStatePtr) return;
// 	g_AppStatePtr->m_aSounds[iSlot].Seek(0);
}

CORELIB_API bool AudioIsPlaying(int iSlot)
{
	if (!g_AppStatePtr) return false;
// 	return g_AppStatePtr->m_aSounds[iSlot].IsPlaying();
	return false;
}

CORELIB_API void AudioMute(bool bMute)
{
	if (!g_AppStatePtr) return;
// 	for (DWORD i=0;i<g_AppStatePtr->m_aSounds.GetCount();i++)
// 		g_AppStatePtr->m_aSounds[i].SetVolume(bMute ? -10000:0);
}

CORELIB_API void Begin2D(void)
{
	//GetBlitter().Begin();
}

CORELIB_API void End2D(void)
{
	//GetBlitter().End();
}

CORELIB_API bool FontLoad(const char *pszFontFile)
{
	std::cerr << "Hello CoreLib::FontLoad\n";
	if (!g_AppStatePtr) return false;
	return true;
}

CORELIB_API void FontPutChar(int iScreenX,int iScreenY,const RECT& rcSource)
{
	if (!g_AppStatePtr) return;
}

CORELIB_API bool SpriteArtLoad(const char *pszArtName,SpriteArt *pArt)
{
	return false;
}

CORELIB_API void SpriteArtUnload(SpriteArt *pArt)
{

}

/*CORELIB_API void SpriteDraw(const SpriteArt *pArt,int iX,int iY,const RECT& rcSrc,bool bFlip,DWORD clrTint, bool bBR)
{
}*/

CORELIB_API void* SplashLoad(const char *pszArtName)
{
	return NULL;
}

CORELIB_API void SplashUnload(void *pSplash)
{
}

CORELIB_API void SplashDraw(void *pSplash,int iX,int iY)
{
}

CORELIB_API void SplashFill(unsigned int clrVal, int top, int left, int bottom, int right)
{
}

} // CoreLib Namespace
